home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
FishMarket 1.0
/
FishMarket v1.0.iso
/
fishies
/
551-575
/
disk_556
/
scheme2c
/
scheme-src.lzh
/
scrt
/
scdebug.sc
< prev
next >
Wrap
Text File
|
1991-10-11
|
11KB
|
313 lines
;;; This module contains code for tracing and breakpointing functions using
;;; the SCHEME->C interpreter. It also contains the code for an error
;;; handler which back traces the control stack.
;* Copyright 1989 Digital Equipment Corporation
;* All Rights Reserved
;*
;* Permission to use, copy, and modify this software and its documentation is
;* hereby granted only under the following terms and conditions. Both the
;* above copyright notice and this permission notice must appear in all copies
;* of the software, derivative works or modified versions, and any portions
;* thereof, and both notices must appear in supporting documentation.
;*
;* Users of this software agree to the terms and conditions set forth herein,
;* and hereby grant back to Digital a non-exclusive, unrestricted, royalty-free
;* right and license under any changes, enhancements or extensions made to the
;* core functions of the software, including but not limited to those affording
;* compatibility with other hardware or software environments, but excluding
;* applications which incorporate this software. Users further agree to use
;* their best efforts to return to Digital any such changes, enhancements or
;* extensions that they make and inform Digital of noteworthy uses of this
;* software. Correspondence should be provided to Digital at:
;*
;* Director of Licensing
;* Western Research Laboratory
;* Digital Equipment Corporation
;* 100 Hamilton Avenue
;* Palo Alto, California 94301
;*
;* This software may be distributed (but not offered for sale or transferred
;* for compensation) to third parties, provided such third parties agree to
;* abide by the terms and conditions of this notice.
;*
;* THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
;* WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
;* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
;* CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
;* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
;* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
;* ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
;* SOFTWARE.
(module scdebug
(top-level
TRACED-PROCS BPT-PROCS *ARGS* *RESULT* DOTRACE TRACER
DOUNTRACE DOBPT DOUNBPT BACKTRACE *DEBUG-ON-ERROR*))
(include "repdef.sc")
;;; Nesting level for traced and breakpointed functions.
(define TRACE-LEVEL 0)
;;; A-lists of traced and breakpointed functions with elements:
;;; (symbol original-procedure debugged-procedure).
(define TRACED-PROCS '())
(define BPT-PROCS '())
;;; Arguments at the time of a breakpoint are in *ARGS*, and the result is in
;;; *RESULT* after the function is called. A new result may be returned by
;;; continuing from the breakpoint with (PROCEED new-value).
(define *ARGS* '())
(define *RESULT* '())
;;; Function tracing
(install-expander
'TRACE
(lambda (x e)
(if (cdr x)
`(map (lambda (f) (dotrace f)) (quote ,(cdr x)))
'(map (lambda (x) (car x)) traced-procs))))
(define (DOTRACE name)
(if (assoc name traced-procs) (dountrace name))
(if (assoc name bpt-procs) (dounbpt name))
(let ((proc (top-level-value name))
(trace-proc #f))
(if (not (procedure? proc))
(error 'TRACE "Argument is not a PROCEDURE name"))
(if (assoc name traced-procs)
(error 'TRACE "~s is already traced" name))
(set! trace-proc (tracer name proc))
(set! traced-procs (cons (list name proc trace-proc) traced-procs))
(set-top-level-value! name trace-proc))
name)
(define (TRACER name proc)
(lambda x
(format stdout-port "~a~s~%"
(make-string (* 2 (min trace-level 15)) #\space)
(cons name x))
(set! trace-level (+ trace-level 1))
(let ((result (apply proc x)))
(set! trace-level (- trace-level 1))
(format stdout-port "~a~a~s~%"
(make-string (* 2 (min trace-level 15)) #\space)
"==> " result)
result)))
(install-expander
'UNTRACE
(lambda (x e)
(if (null? (cdr x))
(set! x (map (lambda (x) (car x)) traced-procs))
(set! x (cdr x)))
`(map (lambda (f) (dountrace f)) (quote ,x))))
(define (DOUNTRACE name)
(let ((name-proc-trace (assoc name traced-procs)))
(if (not name-proc-trace)
(error 'UNTRACE "~s is not traced" name))
(if (eq? (top-level-value name) (caddr name-proc-trace))
(set-top-level-value! name (cadr name-proc-trace)))
(set! traced-procs (remove name-proc-trace traced-procs)))
name)
;;; Function breakpoints
(install-expander
'BPT
(lambda (x e)
(case (length x)
((1) '(map (lambda (x) (car x)) bpt-procs))
((2) `(apply dobpt (quote ,(cdr x))))
((3) (let ((func (e (caddr x) e)))
`(apply dobpt
(list (quote ,(cadr x)) (quote ,func)))))
(else (error 'BPT "Illegal arguments")))))
(define (DOBPT name . condition)
(if (assoc name traced-procs) (dountrace name))
(if (assoc name bpt-procs) (dounbpt name))
(let ((proc (top-level-value name))
(bpt-proc #f))
(if (not (procedure? proc))
(error 'BPT "Argument is not a PROCEDURE name"))
(set! bpt-proc
(bpter name proc (if condition (eval (car condition)))))
(set! bpt-procs (cons (list name proc bpt-proc) bpt-procs))
(set-top-level-value! name bpt-proc))
name)
(define BPTER-PROCNAME "")
(define (BPTER name proc condition)
(define (XEQ . args)
(let ((ftok (enable-system-file-tasks #f)))
(let ((result (apply read-eval-print args)))
(enable-system-file-tasks ftok)
result)))
(lambda x
(set! bpter-procname (c-tscp-ref (stacktrace) 4))
(if (or (not condition) (apply condition x))
(let ((prompt (format "~s- " trace-level)))
(set! *args* x)
(xeq
'header
(format "~%~s -calls - ~s" trace-level
(cons name x))
'prompt
prompt
'env
(dobacktrace bpter-procname "READ-EVAL-PRINT" 20 #f))
(set! trace-level (+ trace-level 1))
(set! *result* (apply proc *args*))
(set! trace-level (- trace-level 1))
(xeq
'header
(format "~s -returns- ~s" trace-level *result*)
'prompt
prompt
'result
*result*
'env
(dobacktrace bpter-procname "READ-EVAL-PRINT" 20 #f)))
(apply proc x))))
(install-expander
'UNBPT
(lambda (x e)
(if (null? (cdr x))
(set! x (map (lambda (x) (car x)) bpt-procs))
(set! x (cdr x)))
`(map (lambda (f) (dounbpt f)) (quote ,x))))
(define (DOUNBPT name)
(let ((name-proc-bpt (assoc name bpt-procs)))
(if (not name-proc-bpt)
(error 'UNBPT "~s is not breakpointed" name))
(if (eq? (top-level-value name) (caddr name-proc-bpt))
(set-top-level-value! name (cadr name-proc-bpt)))
(set! bpt-procs (remove name-proc-bpt bpt-procs)))
name)
;;; The following functions are used to backtrace the control stack. The first
;;; performs an insertion sort to insert a new element into a list.
(define (INSERTION-SORT item sorted-items before?)
(let loop ((next sorted-items) (prev #f))
(cond ((null? next)
(if prev
(begin (set-cdr! prev (list item))
sorted-items)
(list item)))
((not (before? item (car next)))
(loop (cdr next) next))
(prev
(set-cdr! prev (cons item next))
sorted-items)
(else (cons item sorted-items)))))
;;; Backtracing is done by the following function. It accepts a starting
;;; function (or #F), a termination function (or #F), a line count, and an
;;; output port. It returns an environment for use with eval with the
;;; following definitions: all variables defined in the innermost interpreted
;;; environments, and variables of the form env-n whose value is the
;;; environment at that interpreter level.
(define (DOBACKTRACE start stop lines port)
(do ((stp (stacktrace) (c-unsigned-ref stp 0))
(procname "")
(envlist '())
(envid '(env-0 env-1 env-2 env-3 env-4 env-5 env-6 env-7 env-8
env-9 env-10 env-11 env-12 env-13 env-14 env-15 env-16
env-17 env-18 env-19))
(string-out (open-output-string)))
((or (= stp 0)
(= lines 0)
(null? envid)
(and (not start) (equal? procname stop)))
(if envlist
(append (cdr (assq 'env-0 envlist)) envlist)
envlist))
(set! procname (c-tscp-ref stp 4))
(cond (start
(if (equal? start procname) (set! start #f)))
((not (string? procname))
(when port
(write (c-tscp-ref stp 8) string-out)
(let ((expr (get-output-string string-out)))
(if (> (string-length expr) 65)
(display (string-append (substring expr 0 65)
" ...") port)
(display expr port)))
(display " in " port)
(display (car envid) port)
(newline port))
(set! envlist (cons (cons (car envid) procname) envlist))
(set! envid (cdr envid))
(set! lines (- lines 1)))
((member procname
'("SCEVAL_INTERPRETED-PROC" "LOOP [inside EXEC]")))
(else
(when port
(display "(" port)
(display procname port)
(display " ...)" port)
(newline port))
(set! lines (- lines 1))))))
;;; A backtrace at a breakpoint is obtained by the following function.
(define (BACKTRACE . count)
(dobacktrace bpter-procname "READ-EVAL-PRINT" (if count (car count) 20)
stderr-port)
#f)
;;; The default error handler is replaced by the following function when
;;; backtracing on error is desired. It prints the backtrace, and then
;;; enters a read-eval-print loop when *DEBUG-ON-ERROR* is set.
(define *DEBUG-ON-ERROR* #f)
(define (BACKTRACE-ERROR-HANDLER id format-string . args)
(display (format "***** ~a " id) stderr-port)
(display (apply format (cons format-string args)) stderr-port)
(newline stderr-port)
(set! *error-handler* backtrace-error-handler)
(when *debug-on-error*
(let ((env (dobacktrace "ERROR" "READ-EVAL-PRINT" 20 stderr-port))
(ftok (enable-system-file-tasks #f)))
(set! *debug-on-error* #f)
(let loop () (when (char-ready? stdin-port)
(if (not (eof-object?
(read-char stdin-port)))
(loop))))
(read-eval-print 'prompt ">> " 'header #f 'env env)
(enable-system-file-tasks ftok)
(set! *debug-on-error* #t)))
(reset))
;;; Keyboard interrupt signals are handled by the following function. If
;;; the interpreter is currently reading stdin, then this results in a reset.
;;; Otherwise, a stack trace is printed and the debugger is entered. A normal
;;; exit from the debugger results in the Scheme computation continuing.
(define (ON-INTERRUPT sig)
(if *reading-stdin* (reset))
(let ((ftok (enable-system-file-tasks #f))
(start (c-tscp-ref
(c-unsigned-ref (c-unsigned-ref (stacktrace) 0) 0) 4)))
(format stderr-port "~%***** INTERRUPT *****~%")
(dobacktrace start "READ-EVAL-PRINT" 20 stderr-port)
(read-eval-print 'header #f 'prompt ">> "
'env (dobacktrace start "READ-EVAL-PRINT" 20 #f))
(enable-system-file-tasks ftok)))